﻿using System;
using System.Collections.Generic;

namespace Quail.Helpers
{
    /// <summary>
    /// Extensions to object
    /// </summary>
    public static class SingletonFactory
    {
        private static readonly Dictionary<object, Dictionary<Type, object>> SingletonFactoryDict = new Dictionary<object, Dictionary<Type, object>>();

        /// <summary>
        /// Flushes the singletons from the object
        /// </summary>
        /// <param name="owner"></param>
        public static void FlushSingletons(this object owner)
        {
            lock (SingletonFactoryDict)
                SingletonFactoryDict.Remove(owner);
        }

        /// <summary>
        /// Returns a singleton instance of an object of the type T.  When the instance (owner) is no longer needed, you should call FlushSingletons(owner);
        /// </summary>
        /// <typeparam name="T">Any class type</typeparam>
        /// <param name="owner">The instance that should own the singleton</param>
        /// <param name="createParameters">Parameters to pass to a public constructor</param>
        /// <returns>The singleton instance</returns>
        public static T GetSingle<T>(this object owner, params object[] createParameters) where T : class
        {
            var ttype = typeof(T);

            Dictionary<Type, object> singletonDict;

            lock (SingletonFactoryDict)
            {
                if (!SingletonFactoryDict.TryGetValue(owner, out singletonDict))
                {
                    singletonDict = new Dictionary<Type, object>();
                    SingletonFactoryDict.Add(owner, singletonDict);
                }
            }

            lock (singletonDict)
            {
                object o;
                if (singletonDict.TryGetValue(ttype, out o))
                    return (T) o;

                var result = CreateHelper.CreateInstance<T>(createParameters);

                singletonDict[ttype] = result;

                return result;
            }
        }
    }
}
